﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.Profile;
using System.Threading;
using System.Security.Principal;
using System.Configuration;
using System.ServiceModel;

namespace SecurityAgent
{
    public class SecurityAgentProfileProvider : ProfileProvider
    {


        private string _applicationName;
        private string _applicationKey;
        private ProfileProviderServiceReference.ProfileProviderServiceClient _serviceClient;

        private string _serviceEndPoint;

        public ProfileProviderServiceReference.ProfileProviderServiceClient ServiceClient
        {
            get
            {
                if (_serviceClient == null)
                {
                    if (String.IsNullOrEmpty(_serviceEndPoint))
                        _serviceClient = new ProfileProviderServiceReference.ProfileProviderServiceClient();
                    else
                        _serviceClient = new ProfileProviderServiceReference.ProfileProviderServiceClient();

                }

                return _serviceClient;
            }
        }


        private SASIdentity _sasIdentity;

        public string CurrentUserToken
        {
            get
            {
                if (_sasIdentity == null)
                {
                    _sasIdentity = (SASIdentity)Thread.CurrentPrincipal.Identity;
                }

                if (_sasIdentity == null)
                    return string.Empty;
                else
                    return _sasIdentity.UserToken;
            }
        }

        public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
        {
            base.Initialize(name, config);

            _applicationKey = this.GetConfigValue(config["applicationKey"], "");
            _applicationName = this.GetConfigValue(config["applicationName"], "");
            _serviceEndPoint = this.GetConfigValue(config["serviceEndPoint"], "");
        }

        private string GetConfigValue(string configValue, string defaultValue)
        {
            if (String.IsNullOrEmpty(configValue))
                return defaultValue;

            return configValue;
        }


        public override string ApplicationName
        {
            get
            {
                return _applicationName;
            }
            set
            {
                _applicationName = value;
            }
        }


        public override int DeleteInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate)
        {
            throw new NotImplementedException();
        }

        public override int DeleteProfiles(string[] usernames)
        {
            throw new NotImplementedException();
        }

        public override int DeleteProfiles(ProfileInfoCollection profiles)
        {
            throw new NotImplementedException();
        }

        public override ProfileInfoCollection FindInactiveProfilesByUserName(ProfileAuthenticationOption authenticationOption, string usernameToMatch, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override ProfileInfoCollection FindProfilesByUserName(ProfileAuthenticationOption authenticationOption, string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override ProfileInfoCollection GetAllInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override ProfileInfoCollection GetAllProfiles(ProfileAuthenticationOption authenticationOption, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override int GetNumberOfInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate)
        {
            throw new NotImplementedException();
        }

        
        public override System.Configuration.SettingsPropertyValueCollection GetPropertyValues(System.Configuration.SettingsContext context, System.Configuration.SettingsPropertyCollection collection)
        {
            
            SettingsPropertyValueCollection settingsValues = new SettingsPropertyValueCollection();

            try
            {
                bool isAuthenticated = Convert.ToBoolean(context["IsAuthenticated"]);

                if (isAuthenticated)
                {
                    string userName = context["UserName"].ToString();

                    string[] propertyNames = new string[collection.Count];

                    int i = 0;
                    foreach (SettingsProperty p in collection)
                    {
                        propertyNames[i] = p.Name;
                        i++;
                    }



                    ProfileProviderServiceReference.ProfilePropertyValueCollection result = ServiceClient.GetPropertyValues(_applicationKey, CurrentUserToken, userName, propertyNames);


                    foreach (System.Configuration.SettingsProperty prop in collection)
                    {
                        SettingsPropertyValue value = new SettingsPropertyValue(prop);
                        value.PropertyValue = new object();
                        if (result != null)
                        {
                            foreach (ProfilePropertyValue v in result)
                            {
                                if (v.PropertyName == prop.Name)
                                {
                                    value.PropertyValue = Convert.ChangeType(v.PropertyValue, prop.PropertyType);
                                    break;
                                }
                            }
                        }
                        settingsValues.Add(value);
                    }

                }

            }
            catch (FaultException<UnauthorizedAccessFault> e1)
            {
                throw new UnauthorizedAccessException(e1.Detail);
            }
            catch (FaultException<SecurityFault> e2)
            {
                throw new GeneralSecurityException(e2.Detail);
            }
            catch (FaultException e3)
            {
                throw new Exception(e3.Message + ":" + e3.Reason);
            }
            
            return settingsValues;
        }

        public override void SetPropertyValues(System.Configuration.SettingsContext context, System.Configuration.SettingsPropertyValueCollection collection)
        {
            
            if (collection == null && collection.Count == 0) return;

            ProfilePropertyValue[] values = new ProfilePropertyValue[collection.Count];

            int i = 0;
            foreach (SettingsPropertyValue value in collection)
            {
                values[i] = new ProfilePropertyValue { PropertyValue = value.PropertyValue.ToString().Trim(), PropertyName = value.Name };
                i++;
            }

            try
            {
                bool isAuthenticated = Convert.ToBoolean(context["IsAuthenticated"]);
                if (isAuthenticated)
                {
                    string userName = context["UserName"].ToString();

                    ServiceClient.SetPropertyValues(_applicationKey, CurrentUserToken, userName, values);
                }
            }
            catch (FaultException<UnauthorizedAccessFault> e1)
            {
                throw new UnauthorizedAccessException(e1.Detail);
            }
            catch (FaultException<SecurityFault> e2)
            {
                throw new GeneralSecurityException(e2.Detail);
            }
            catch (FaultException e3)
            {
                throw new Exception(e3.Message + ":" + e3.Reason);
            }
            
        }
    }
}
